﻿using GreenPipes;
using MassTransit;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;


namespace Infrastructure.MessageBus
{
    public static class MessageBusExtensions
    {
        public static Task<ISendEndpoint> GetSendEndpoint(this IBus bus, string ServiceName)
        {
            var url = new System.Uri($"rabbitmq://{bus.Address.Host}/{ServiceName}");

            return bus.GetSendEndpoint(url);
        }
        public static IApplicationBuilder UseMessageBus(this IApplicationBuilder app, IHostApplicationLifetime lifetime)
        {
            var bus = app.ApplicationServices.GetService<IBus>();

            lifetime.ApplicationStarted.Register(((IBusControl)bus).Start);
            lifetime.ApplicationStopped.Register(((IBusControl)bus).Stop);


            return app;
        }
        public static void AddAdminMessageBus(this IServiceCollection services, IConfiguration configuration, string QueuePrifx, string AdminQueuePrifx)
        {
            MessageBusQueueNameUtils.QueueNamePrifx = QueuePrifx;
            MessageBusAdminQueueNameUtils.QueueNamePrifx = AdminQueuePrifx;
            var connectionStr = configuration.GetValue<string>("RabbitMQ.ConnectionStr");
            var connectionArr = connectionStr.Split(",");


            services.AddSingleton<IBus>(i =>
            {
                var BusControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
                {
                    var strArr = connectionArr[0].Split(";");

                    var hostStr = strArr[0].Split("=")[1];
                    var virtualHostStr = strArr[1].Split("=")[1];
                    var usernameStr = strArr[2].Split("=")[1];
                    var passwordStr = strArr[3].Split("=")[1];

                    cfg.Host(hostStr, virtualHostStr, h =>
                    {
                        h.Username(usernameStr);
                        h.Password(passwordStr);
                        h.PublisherConfirmation = true;
                        h.Heartbeat(10);                        

                        if (connectionArr.Count() > 0)
                        {
                            h.UseCluster(j =>
                            {
                                for (int u = 0; u < connectionArr.Count(); u++)
                                {
                                    var strArr1 = connectionArr[u].Split(";");
                                    var hostStr1 = strArr1[0].Split("=")[1];

                                    j.Node(hostStr1);
                                }
                            });
                        }
                    });

                    //启动时清除现有队列中的消息
                    cfg.PurgeOnStartup = false;
                    cfg.PrefetchCount = 10;

                    var itype = typeof(DomainEvent.IDomainEventHandler<>);
                    var assembly = Assembly.Load("Application");
                    var AllHandlers = assembly.ExportedTypes.Where(gi => gi.FullName.StartsWith("Application.Admin.Event") && gi.BaseType.FullName.StartsWith($"{itype.Namespace}.{itype.Name}[["));


                    foreach (var Queue in MessageBusAdminQueueNameUtils.GetQueueName())
                    {
                        var Handlers = AllHandlers;

                        if (Handlers.Count() == 0) continue;

                        cfg.ReceiveEndpoint(Queue.Item2, e =>
                        {
                            e.Durable = true;
                            e.UseBsonSerializer();
                            //e.PurgeOnStartup = false;
                            //e.PrefetchCount = 64;
                            // Retry
                            e.UseRetry(ret =>
                            {
                                ret.Interval(2, TimeSpan.FromSeconds(2)); // 每隔10s重试一次，最多重试3次
                            });

                            e.UseConcurrencyLimit(5);
                            e.UseRateLimit(1000, TimeSpan.FromSeconds(10)); // 100s内限1000次访问请求

                            // CircuitBreaker
                            e.UseCircuitBreaker(cb =>
                            {
                                cb.TrackingPeriod = TimeSpan.FromMinutes(1); // 跟踪周期：1min
                                cb.TripThreshold = 50; // 失败比例达到15%后才会打开熔断器
                                cb.ActiveThreshold = 8; // 至少发生5次请求后才会打开熔断器
                                cb.ResetInterval = TimeSpan.FromMinutes(3); // 熔断时间间隔：5mins
                            });

                            //e.SetQueueArgument("x-expires", config.timeout * 1000 /*Seconds to milliseconds*/);
                            //e.SetQueueArgument("temporary", config.temporary);

                            e.AutoDelete = false;
                            //e.ConfigureDeadLetter(i =>
                            //{
                                
                            //});
                            e.BindDeadLetterQueue("error");

                            e.DeadLetterExchange = "error";
                            e.Lazy = false;


                            foreach (var item in Handlers)
                            {
                                e.Consumer(item, ug =>
                                {
                                    var instance = assembly.CreateInstance(ug.FullName);
                                    return instance;
                                });
                            }

                        });
                    }



                });

                return BusControl;
            });

        }

        public static void AddMessageBus(this IServiceCollection services, IConfiguration configuration, string QueuePrifx, string AdminQueuePrifx)
        {
            MessageBusQueueNameUtils.QueueNamePrifx = QueuePrifx;
            MessageBusAdminQueueNameUtils.QueueNamePrifx = AdminQueuePrifx;
            var connectionStr = configuration.GetValue<string>("RabbitMQ.ConnectionStr");
            var connectionArr = connectionStr.Split(",");


            services.AddSingleton<IBus>(i =>
            {
                var BusControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
                {
                    var strArr = connectionArr[0].Split(";");

                    var hostStr = strArr[0].Split("=")[1];
                    var virtualHostStr = strArr[1].Split("=")[1];
                    var usernameStr = strArr[2].Split("=")[1];
                    var passwordStr = strArr[3].Split("=")[1];

                    cfg.Host(hostStr, virtualHostStr, h =>
                    {
                        h.Username(usernameStr);
                        h.Password(passwordStr);
                        h.PublisherConfirmation = true;
                        h.Heartbeat(10);

                        if (connectionArr.Count() > 0)
                        {
                            h.UseCluster(j =>
                            {
                                for (int u = 0; u < connectionArr.Count(); u++)
                                {
                                    var strArr1 = connectionArr[u].Split(";");
                                    var hostStr1 = strArr1[0].Split("=")[1];

                                    j.Node(hostStr1);
                                }
                            });
                        }
                    });

                    
                    //启动时清除现有队列中的消息
                    cfg.PurgeOnStartup = false;
                    cfg.PrefetchCount = 10;

                    var itype = typeof(DomainEvent.IDomainEventHandler<>);
                    var assembly = Assembly.Load("Application");
                    var AllHandlers = assembly.ExportedTypes.Where(gi => gi.FullName.StartsWith("Application.Event") && gi.BaseType.FullName.StartsWith($"{itype.Namespace}.{itype.Name}[["));


                    foreach (var Queue in MessageBusQueueNameUtils.GetQueueName())
                    {
                        var Handlers = AllHandlers;

                        if (Handlers.Count() == 0) continue;

                        cfg.ReceiveEndpoint(Queue.Item2, e =>
                        {
                            e.Durable = true;
                            e.UseBsonSerializer();
                            //e.PurgeOnStartup = false;
                            //e.PrefetchCount = 64;
                            // Retry
                            e.UseRetry(ret =>
                            {
                                ret.Interval(2, TimeSpan.FromSeconds(2)); // 每隔10s重试一次，最多重试3次
                            });

                            e.UseConcurrencyLimit(5);
                            e.UseRateLimit(1000, TimeSpan.FromSeconds(10)); // 100s内限1000次访问请求

                            // CircuitBreaker
                            e.UseCircuitBreaker(cb =>
                            {
                                cb.TrackingPeriod = TimeSpan.FromMinutes(1); // 跟踪周期：1min
                                cb.TripThreshold = 50; // 失败比例达到15%后才会打开熔断器
                                cb.ActiveThreshold = 8; // 至少发生5次请求后才会打开熔断器
                                cb.ResetInterval = TimeSpan.FromMinutes(3); // 熔断时间间隔：5mins
                            });

                            //e.SetQueueArgument("x-expires", config.timeout * 1000 /*Seconds to milliseconds*/);
                            //e.SetQueueArgument("temporary", config.temporary);

                            e.AutoDelete = false;
                            e.BindDeadLetterQueue("error");

                            e.DeadLetterExchange = "error";
                            e.Lazy = false;


                            foreach (var item in Handlers)
                            {
                                e.Consumer(item, ug =>
                                {
                                    var instance = assembly.CreateInstance(ug.FullName);                                    
                                    return instance;
                                });
                            }
                        });
                    }
                });

                return BusControl;
            });

        }


    }
}
